package com.ygnn.service;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;

import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.ygnn.common.Pojo.Order;
import com.ygnn.common.Vo.WxPayRespVO;
import com.ygnn.common.context.BaseContext;
import com.ygnn.common.utils.HttpRequestHelper;
import com.ygnn.config.WxHttpRequest;
import com.ygnn.config.WxInformation;
import com.ygnn.config.WxWayJsapi;
import com.ygnn.mapper.OrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * ClassName:WxPayService
 * Package:com.ygnn.service
 * Description:
 *
 * @Author: dlh
 * @Creat:2024/10/29-15:40
 */
@Slf4j
@Service
public class WxPayService {

    @Resource
    private WxInformation wxInformation;
    @Resource
    private WxWayJsapi wxWayJsapi;
    @Resource
    private WxHttpRequest wxHttpRequest;
    @Autowired
    private OrderMapper orderMapper;

    public WxPayRespVO nativePay(String description, String amount, String outTradeNo) throws IOException, GeneralSecurityException, HttpCodeException, NotFoundException, URISyntaxException {
        log.info("调用统一下单API");
        String openID = BaseContext.getCurrentId();
        //设置微信请求url
        HttpPost httpPost = new HttpPost(wxInformation.getWxUrl().concat(wxWayJsapi.getOrder()));
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json;charset=utf-8");
        // 请求body参数
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("mchid", wxInformation.getMchId())
                .put("appid", wxInformation.getPublicAppid())
                .put("description", description)
                .put("notify_url", wxInformation.getNotifyUrl())
                .put("out_trade_no", outTradeNo);
        //总金额，单位为分
        Integer amount1 = Integer.valueOf(amount);

        rootNode.putObject("amount")
                .put("total", amount1);
        rootNode.putObject("payer")
                .put("openid", openID);
        log.info("请求参数 ===> " + rootNode);
        objectMapper.writeValue(bos, rootNode);
        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        /**
         * 完成签名并执行请求
         * */
        CloseableHttpResponse response = wxHttpRequest.sendWX(wxHttpRequest.getVerifier()).execute(httpPost);
        if (response != null) {
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("返回的prepay_id是 =====》 " + bodyAsString);

            JSONObject bodyobj = JSONObject.parseObject(bodyAsString);
            String prepayId = (String) bodyobj.get("prepay_id");
            WxPayRespVO vo = new WxPayRespVO();
            Long timeStamp = System.currentTimeMillis() / 1000;
            vo.setTimeStamp(timeStamp + "");
            String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
            vo.setNonceStr(substring);
            String signatureStr = Stream.of(wxInformation.getPublicAppid(), String.valueOf(timeStamp), substring, "prepay_id=" + prepayId)
                    .collect(Collectors.joining("\n", "", "\n"));
            String sign = HttpRequestHelper.getSign(signatureStr, wxInformation.getPrivateKeyPath());
            vo.setPaySign(sign);
            vo.setPrepayId("prepay_id=" + prepayId);
            return vo;
        }
        return new WxPayRespVO();
    }

    public Map payNotify(HttpServletRequest request) {
        Map<String, String> result = new HashMap();
        try {
            String requestBody = HttpRequestHelper.getRequestBody(request);
            log.info("支付成功响应数据是： " + requestBody);
            JSONObject requestBodyJson = JSONObject.parseObject(requestBody);
            //微信返回的证书序列号
            String serialNo = request.getHeader("Wechatpay-Serial");
            //微信返回的随机字符串
            String nonceStr = request.getHeader("Wechatpay-Nonce");
            //微信返回的时间戳
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            //微信返回的签名
            String wechatSign = request.getHeader("Wechatpay-Signature");
            // 构建request，传入必要参数
            NotificationRequest request1 = new NotificationRequest.Builder().withSerialNumber(serialNo)
                    .withNonce(nonceStr)
                    .withTimestamp(timestamp)
                    .withSignature(wechatSign)
                    .withBody(requestBody)
                    .build();
            NotificationHandler handler = new NotificationHandler(wxHttpRequest.getVerifier().getVerifier(wxInformation.getMchId()), wxInformation.getV3Key().getBytes(StandardCharsets.UTF_8));
            // 验签和解析请求体
            Notification notification = handler.parse(request1);
            // 从notification中获取解密报文
            log.info("支付成功获取解密报文： " + notification.getDecryptData());
            if (notification.getDecryptData() != null) {
                if ("TRANSACTION.SUCCESS".equals(requestBodyJson.get("event_type") + "")) {
                    JSONObject resourcePayJson = JSONObject.parseObject(notification.getDecryptData());
                    //根据微信之后返回的结果对订单进行不同的处理
                    if ("SUCCESS".equals(resourcePayJson.get("trade_state") + "")) {
                        String amount = resourcePayJson.getJSONObject("amount").get("total") + "";
                        String openid = resourcePayJson.getJSONObject("payer").get("openid") + "";
                        String outTradeNo = (String) resourcePayJson.get("out_trade_no");
                        //交易成功处理逻辑：
                        //1.检查订单状态，如果已处理，则直接返回结果成功
                        Order order=orderMapper.selectByOrderId(Long.valueOf(outTradeNo));
                        if (order.getStatus()!=Order.NoPay){
                            //订单已支付
                            result.put("code", "SUCCESS");
                            result.put("message", "成功");
                            return result;
                        }
                        //2.更新订单状态
                        orderMapper.updateByOrderId(Long.valueOf(outTradeNo),Order.ING);

                        log.info("订单商户订单号：" + outTradeNo + "\t支付成功\t" + "用户openId：" + openid + "\t用户支付金额：" + amount);
                    } else {
                        log.info("微信返回支付失败： 失败单号" + resourcePayJson.get("out_trade_no") + "失败状态" + resourcePayJson.get("trade_state"));
                    }
                } else {
                    log.error("微信返回支付错误摘要：" + requestBodyJson.get("summary"));
                }
            }
        } catch (Exception e) {
            result.put("code", "FAIL");
            result.put("message", "系统错误");
        }
        result.put("code", "SUCCESS");
        result.put("message", "成功");
        return result;
    }
}
